//strings 处理Unicode字符和经过UTF-8 编码的字符串。
//bytes 主要面对字节和字节切片。
package BufferTest

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strings"
)

//被真正使用后部不可复制
//并发不安全
func StringsBuildTest() {
	var builder1 strings.Builder
	fmt.Println("Grow the builder ...")
	builder1.Grow(10)
	fmt.Printf("The length of contents in the builder is %d.\n", builder1.Len())

	b3 := builder1
	//b3.Grow(3) Panic
	_ = b3

	f2 := func(bp *strings.Builder) {
		(*bp).Grow(1) // 这里虽然不会引发panic，但不是并发安全的。
		builder4 := *bp
		//builder4.Grow(1) // 这里会引发panic。
		_ = builder4
	}
	f2(&builder1)
	//未使用的build可以复制
	builder1.Reset()
	builder5 := builder1
	builder5.Grow(1) // 这里不会引发panic。
}

func StringsReadTest() {
	var reader1 strings.Reader
	readingIndex := reader1.Size() - int64(reader1.Len()) // 计算出的已读计数。

	offset2 := int64(17)
	expectedIndex := reader1.Size() - int64(reader1.Len()) + offset2
	fmt.Printf("Seek with offset %d and whence %d ...\n", offset2, io.SeekCurrent)
	readingIndex, _ = reader1.Seek(offset2, io.SeekCurrent)
	fmt.Printf("The reading index in reader: %d (returned by Seek)\n", readingIndex)
	fmt.Printf("The reading index in reader: %d (computed by me)\n", expectedIndex)
}

//Buffer值的长度是未读内容的长度，而不是已存内容的总长度
func BytesTest() {
	var buffer1 bytes.Buffer
	contents := "Simple byte buffer for marshaling data."
	fmt.Printf("Writing contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
}

var buf *bytes.Buffer

//bytes.Buffer可能造成内容泄露
func BufUnsafeTest() {
	newBuffer()
	b := getUnread()
	b[0] = 49
	fmt.Println(b)
	b = getUnread()
	fmt.Println(b)
}
func newBuffer() {
	t := []byte{97, 98}
	buf = bytes.NewBuffer(t)
}

func getUnread() []byte {
	unreadBytes := buf.Bytes()
	fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes)
	var returnByte []byte
	err := deepCopy(&unreadBytes, &returnByte)
	if err != nil {
		fmt.Println(err)
		return nil
	}
	return returnByte
}

func deepCopy(src, dst interface{}) (err error) {
	if reflect.TypeOf(dst).Kind() != reflect.Ptr {
		return errors.New("目标对象必须是指针？")
	}
	var buf bytes.Buffer
	err = gob.NewEncoder(&buf).Encode(src)
	if err != nil {
		return
	}
	err = gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
	return
}
